package com.mxpio.erp.asset.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.mxpio.erp.common.enums.BorrowApplyEnums;
import com.mxpio.erp.common.vo.OrderExcuteLineVo;
import com.mxpio.erp.common.vo.OrderExcuteVo;
import com.mxpioframework.common.exception.MBootException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.mxpio.erp.common.asset.entity.BorrowApply;
import com.mxpio.erp.common.asset.entity.BorrowApplyLine;
import com.mxpio.erp.common.asset.entity.BorrowOutMaterial;
import com.mxpio.erp.common.asset.entity.BorrowOutMaterialFlow;
import com.mxpio.erp.common.asset.service.BorrowApplyLineService;
import com.mxpio.erp.common.asset.service.BorrowApplyService;
import com.mxpio.erp.common.asset.service.BorrowOutMaterialFlowService;
import com.mxpio.erp.common.asset.service.BorrowOutMaterialService;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums.BpmnStatus;
import com.mxpio.erp.common.enums.OrderStatusEnums.CloseStatus;
import com.mxpio.erp.common.inventory.entity.VInvLotStock;
import com.mxpioframework.common.vo.Result;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.jpa.query.Operator;
import com.mxpioframework.security.util.SecurityUtils;
import com.mxpioframework.system.service.impl.BaseServiceImpl;

@Service
public class BorrowApplyServiceImpl extends BaseServiceImpl<BorrowApply> implements BorrowApplyService{
	@Autowired
	private BorrowApplyLineService borrowApplyLineService;
	@Autowired
	private BorrowOutMaterialService borrowOutMaterialService;
	@Autowired
	private BorrowOutMaterialFlowService borrowOutMaterialFlowService;
	
	@Override
	@Transactional(readOnly = false)
	public Result<BorrowApply> updateCloseStatus(String bizNo, CloseStatus closeStatus) {
		BorrowApply wo = this.getById(BorrowApply.class,bizNo);
		if(wo==null) {
			return Result.error("申请单号未能查询到数据，请确认");
		}
		if(CloseStatus.CLOSED.equals(closeStatus) && wo.getCloseStatus().equals(OrderStatusEnums.CloseStatus.CLOSED.getStatusCode())){
			return Result.error("非打开状态不可关闭");
		}else if(CloseStatus.OPEN.equals(closeStatus) && wo.getCloseStatus().equals(OrderStatusEnums.CloseStatus.OPEN.getStatusCode())){
			return Result.error("非关闭状态不可打开");
		}
		wo.setCloseStatus(closeStatus.getStatusCode());
        this.update(wo);
        return Result.OK(wo);
	}
	
	@Override
	@Transactional(readOnly = false)
	public Result<BorrowApply> updateBpmnStatus(String bizNo, BpmnStatus bpmnStatus) {
		BorrowApply wo = this.getById(BorrowApply.class,bizNo);
		if(wo==null) {
			return Result.error("申请单号未能查询到数据，请确认");
		}
		if(bpmnStatus.getStatusCode().equals(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode())&&!wo.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode())){
    		return Result.error("非开立状态不可提交");
		}
		if(bpmnStatus.getStatusCode().equals(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode())&&!wo.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode())){
    		return Result.error("非审核中状态不可审核");
		}
		if(bpmnStatus.getStatusCode().equals(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode())&&
				!(wo.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode())||wo.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode()))){
    		return Result.error("非审核中、已审核状态不可弃审");
		}
		wo.setBpmnStatus(bpmnStatus.getStatusCode());
		wo.setReviewer(SecurityUtils.getLoginUsername());
		wo.setReviewTime(new Date());
		wo.setReturnStatus(BorrowApplyEnums.ReturnStatus.APPLY.getTypeCode());//更新归还状态
        this.update(wo);
        return Result.OK(wo);
	}

	@Override
	@Transactional(readOnly = false)
	public Result<BorrowApply> execute(String bizNo,String applyType, OrderExcuteVo orderExcuteVo) {
		BorrowApply wo = this.getById(BorrowApply.class,bizNo);
		if(wo==null) {
			throw new MBootException("申请单号未能查询到数据，请确认");
			//return Result.error("申请单号未能查询到数据，请确认");
		}
		if(wo.getCloseStatus().equals(OrderStatusEnums.CloseStatus.CLOSED.getStatusCode())) {
			//return Result.error("已关闭状态不可执行");
			throw new MBootException("已关闭状态不可执行");
		}
		//Criteria c = Criteria.create().addCriterion("bizNo", Operator.EQ, bizNo);
		//List<BorrowApplyLine> lines = borrowApplyLineService.list(BorrowApplyLine.class, c);
		List<OrderExcuteLineVo> lines = orderExcuteVo.getLines();//

		if(lines==null||lines.size()==0) {
			//return Result.error("申请单物资明细无执行数据，无法执行");
			throw new MBootException("申请单物资明细无执行数据，无法执行");
		}

		//wo.setApplyType(applyType);
		List<BorrowOutMaterialFlow> insertMaterialFlows = new ArrayList<>();
		if("0".equals(applyType)) {//借出
			if(!wo.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode())){
				//return Result.error("非已审核状态不可执行");
				throw new MBootException("非已审核状态不可执行认");
			}

			if(StringUtils.equals(wo.getOrderStatus(), OrderStatusEnums.OrderStatus.FINISHED.getStatusCode())) {
				//return Result.error("申请单已执行，不能重复执行");
				throw new MBootException("申请单已执行，不能重复执行");
			}
			for(OrderExcuteLineVo line:lines) {
				//1 查询库存视图
				List<VInvLotStock> stocks = JpaUtil.linq(VInvLotStock.class)
						.equal("itemCode", line.getItemCode())
						.equal("lotNo", line.getLotNo())
						.equal("whCode", line.getWhCode()).list();
				if(stocks.size()==0) {
					//return Result.error("申请借用的物资"+line.getItemCode()+"【"+line.getLotNo()+"】没有对应库存记录");
					throw new MBootException("申请借用的物资"+line.getItemCode()+"【"+line.getLotNo()+"】没有对应库存记录");
				}
				VInvLotStock stock= stocks.get(0);
				BigDecimal quantity = stock.getQuantity();
				BigDecimal borrowedQuantity = stock.getBorrowedQuantity();
				BigDecimal applyNum = line.getQuantity();
				if(quantity.compareTo(borrowedQuantity)<=0) {
					//return Result.error("申请借用的物资已借用数量已不满足借用条件(不大于库存)");
					throw new MBootException("申请借用的物资已借用数量已不满足借用条件(不大于库存)");
				}
				if(quantity.compareTo(borrowedQuantity.add(applyNum))<0) {
					//return Result.error("本次申请借用的物资借用数量已不满足借用条件(不大于可借数量)");
					throw new MBootException("本次申请借用的物资借用数量已不满足借用条件(不大于可借数量)");
				}
				//
				Criteria cMaterial = Criteria.create().addCriterion("itemCode", Operator.EQ, line.getItemCode())
						.addCriterion("whCode", Operator.EQ, line.getWhCode())
						.addCriterion("lotNo", Operator.EQ, line.getLotNo());
				List<BorrowOutMaterial> dbBorrowOutMaterials = borrowOutMaterialService.list(BorrowOutMaterial.class, cMaterial);
				if(dbBorrowOutMaterials==null||dbBorrowOutMaterials.size()==0) {
					BorrowOutMaterial addMaterial = new BorrowOutMaterial();
					addMaterial.setItemCode(line.getItemCode());
					addMaterial.setWhCode(line.getWhCode());
					addMaterial.setLotNo(line.getLotNo());
					addMaterial.setQuantity(line.getQuantity());
					borrowOutMaterialService.save(addMaterial);
				}else {
					BorrowOutMaterial updateMaterial = dbBorrowOutMaterials.get(0);
					updateMaterial.setQuantity(line.getQuantity().add(updateMaterial.getQuantity()));
					borrowOutMaterialService.update(updateMaterial);
				}
				BorrowOutMaterialFlow newMaterialFlow = new BorrowOutMaterialFlow();
				newMaterialFlow.setItemCode(line.getItemCode());
				newMaterialFlow.setWhCode(line.getWhCode());
				newMaterialFlow.setLotNo(line.getLotNo());
				newMaterialFlow.setQuantity(line.getQuantity());
				newMaterialFlow.setOriginBizType(applyType);//1 还，0 借
				newMaterialFlow.setOriginBizNo(line.getBizOrderNo());
				newMaterialFlow.setOriginBizLineNo(line.getBizOrderlineNo());
				newMaterialFlow.setOptMan(SecurityUtils.getLoginUsername());
				newMaterialFlow.setAccessType(applyType);
				insertMaterialFlows.add(newMaterialFlow);
			}
			wo.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
			wo.setExecutor(SecurityUtils.getLoginUsername());
			wo.setExecuteTime(new Date());
			wo.setReturnStatus(BorrowApplyEnums.ReturnStatus.BORROWED.getTypeCode());//更新借出状态为已借出
		}else {
			for(OrderExcuteLineVo line:lines) {
				Criteria cMaterial = Criteria.create().addCriterion("itemCode", Operator.EQ, line.getItemCode())
						.addCriterion("whCode", Operator.EQ, line.getWhCode())
						.addCriterion("lotNo", Operator.EQ, line.getLotNo());
				List<BorrowOutMaterial> dbBorrowOutMaterials = borrowOutMaterialService.list(BorrowOutMaterial.class, cMaterial);
				/*if(dbBorrowOutMaterials.size()==0) {
					return Result.error("申请归还的物资"+line.getItemCode()+"没有对应借用记录");
				}
				BorrowOutMaterial borrowOutMaterial = dbBorrowOutMaterials.get(0);
				BigDecimal quantity = borrowOutMaterial.getQuantity();
				BigDecimal applyNum = line.getQuantity();
				if(quantity.compareTo(BigDecimal.ZERO)==0) {
					return Result.error("申请归还的物资已借用数量为零");
				}
				if(quantity.compareTo(applyNum)<0) {
					return Result.error("本次申请归还的物资借用数量已不满足归还条件(不大于已借数量)");
				}*/

				Criteria flowOutCriteria = Criteria.create().addCriterion("originBizNo", Operator.EQ, line.getBizOrderNo())
						.addCriterion("originBizLineNo", Operator.EQ, line.getBizOrderlineNo())
						.addCriterion("itemCode", Operator.EQ, line.getItemCode())
						.addCriterion("accessType", Operator.EQ, "0")
						.addCriterion("lotNo", Operator.EQ, line.getLotNo());

				List<BorrowOutMaterialFlow> singleLotMaterialFlowList = borrowOutMaterialFlowService.list(BorrowOutMaterialFlow.class, flowOutCriteria);//查找对应批号的借出流水记录
				if (singleLotMaterialFlowList.size()==0){
					//return Result.error("提交的数据未匹配到对应批次的借出物资"+line.getItemCode()+"【"+line.getLotNo()+"】");
					throw new MBootException("提交的数据未匹配到对应批次的借出物资"+line.getItemCode()+"【"+line.getLotNo()+"】");
				}
				BigDecimal returnedSumQuantity = borrowOutMaterialFlowService.getSingleOutFlowLotReturnedSum(line.getBizOrderNo(),line.getBizOrderlineNo(),line.getLotNo());
				BigDecimal applyNum = line.getQuantity();
				//BigDecimal lineQuantity = line.getLineQuantity();//执行行数量
				if(singleLotMaterialFlowList.get(0).getQuantity().compareTo(applyNum.add(returnedSumQuantity))<0) {
					//return Result.error("本次申请归还的物资"+line.getItemCode()+"【"+line.getLotNo()+"】数量不能大于待归还数量");
					throw new MBootException("本次申请归还的物资"+line.getItemCode()+"【"+line.getLotNo()+"】数量不能大于待归还数量");
				}
				//更新已借用物资表对应数量
				BorrowOutMaterial updateMaterial = dbBorrowOutMaterials.get(0);
				updateMaterial.setQuantity(updateMaterial.getQuantity().subtract(line.getQuantity()));
				borrowOutMaterialService.update(updateMaterial);
				//updateMaterials.add(updateMaterial);
				BorrowOutMaterialFlow newMaterialFlow = new BorrowOutMaterialFlow();
				newMaterialFlow.setItemCode(line.getItemCode());
				newMaterialFlow.setWhCode(line.getWhCode());
				newMaterialFlow.setLotNo(line.getLotNo());
				newMaterialFlow.setQuantity(line.getQuantity());
				newMaterialFlow.setOriginBizType(applyType);//1 还，0 借
				newMaterialFlow.setOriginBizNo(line.getBizOrderNo());
				newMaterialFlow.setOriginBizLineNo(line.getBizOrderlineNo());
				newMaterialFlow.setAccessType(applyType);
				newMaterialFlow.setOptMan(SecurityUtils.getLoginUsername());
				insertMaterialFlows.add(newMaterialFlow);
			}
			if (wo.getReturnStatus().equals(BorrowApplyEnums.ReturnStatus.BORROWED.getTypeCode())){
				wo.setReturnStatus(BorrowApplyEnums.ReturnStatus.RETURNING.getTypeCode());
			}
		}
		borrowOutMaterialFlowService.save(insertMaterialFlows);
		if("1".equals(applyType)) {//如果是归还，最后查询整单的归还操作情况
			Criteria c = Criteria.create().addCriterion("bizNo", Operator.EQ, bizNo);
			List<BorrowApplyLine> applyLineList = borrowApplyLineService.list(BorrowApplyLine.class, c);
			if (applyLineList.size()>0){
				borrowApplyLineService.handleBorrowApplyLinesReturnedQuantity(applyLineList);//关联已归还数量
				if (checkBorrowApplyReturnedClear(applyLineList)){//如果归还完毕，更新借用状态字段
					wo.setReturnStatus(BorrowApplyEnums.ReturnStatus.CLEAR.getTypeCode());//已还清
				}
			}


		}
		this.update(wo);
		return Result.OK(wo);
	}
	private Boolean checkBorrowApplyReturnedClear(List<BorrowApplyLine> applyLineList){
		if (applyLineList==null||applyLineList.size()==0){
			return false;
		}
		for (BorrowApplyLine line :applyLineList){
			if (line.getQuantity().compareTo(line.getActualQuantity())!=0){
				return false;
			}
		}
		return true;
	}
}
